﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Sustainalytics.Synchronization.Interface;
using System.Diagnostics;
using Sustainalytics.ClientDW.DataAccessLayer;
using System.Collections.Concurrent;
using Sustainalytics.ReportGenerator.BL;
using Sustainalytics.DataLayer.Shared;
using Sustainalytics.Entities;
using Sustainalytics.CompanyReportSyncStep.Exceptions;
using Sustainalytics.Utils;
using Sustainalytics.CompanyReportSyncStep.CompanyReportOnline;
using Sustainalytics.ClientDW.Entities;

namespace Sustainalytics.Synchronization.BusinessLogic
{
    public class ReportDataPreparationSyncStep : ISyncStep
    {
        public SyncStepOrder ExecutionOrder
        {
            get { return SyncStepOrder.ReportDataPreparation; }
        }
        
        public SyncContext Start(SyncContext syncContext)
        {

            if (!syncContext.ConnectionStrings.ContainsKey("ESGComputeServiceAddress"))
                throw new ArgumentException("ESGComputeServiceAddress key is missing!");

            var esgComputeAddressString = syncContext.ConnectionStrings["ESGComputeServiceAddress"];


            if (!syncContext.ConnectionStrings.ContainsKey("MongoDbClientDWConnectionString"))
                throw new ArgumentException("MongoDbClientDWConnectionString key is missing!");

            var clientDwConnectionString = syncContext.ConnectionStrings["MongoDbClientDWConnectionString"];
            var clientDwRepository = ClientDwRepository.GetInstance(clientDwConnectionString);


            if (!syncContext.ConnectionStrings.ContainsKey("MongoDBDWArchiveConnectionString"))
                throw new ArgumentException("MongoDBDWArchiveConnectionString key is missing!");

            var dwArchiveConnectionString = syncContext.ConnectionStrings["MongoDBDWArchiveConnectionString"];


            // check for task cancellation
            syncContext.Token.ThrowIfCancellationRequested();

            var sw = Stopwatch.StartNew();



            if (!syncContext.ConnectionStrings.ContainsKey("MongoDBClientPlatformConnectionString"))
                throw new ArgumentException("MongoDBClientPlatformConnectionString key is missing!");

            var defaultEsgProfile = (new RepositoryCollection<ESGProfile>(syncContext.ConnectionStrings["MongoDBClientPlatformConnectionString"]))
                .ReadAllWhereFieldEqualsValue<string>("Name", "Default", null, 1).SingleOrDefault();

            if (defaultEsgProfile == null)
            {
                throw new DefaultProfileNotFoundException("default profile not found");
            }


            var esgRatingsCache = new ESGRatingsCache(esgComputeAddressString, defaultEsgProfile);
            var esgRatingsTask = esgRatingsCache.GetRatingsAsync();


            var historyRepository = new RepositoryCollection<CompanyHistoricalDataIndicators>(dwArchiveConnectionString);
            var companyHistoricalDataIndicators = historyRepository.ReadAll();

            var last12MonthsAgo = DateTime.UtcNow.Date.AddMonths(-12);


            var companyIds = clientDwRepository.GetCompanyIdsInStandardIndicators();


            var historicalPerformance = new ConcurrentBag<CompanyHistoricalPerformance>();

            var companyPerformance = new ConcurrentBag<CompanyPerformance>();

            Parallel.ForEach(companyIds.Batch(100), (ids) =>
            {
                //var repository = ClientDwRepository.GetInstance(clientDwConnectionString);
                
                
                foreach (var companyId in ids)
                {
                    historicalPerformance.Add(new CompanyHistoricalPerformance
                    {
                        Id = companyId,
                        Last36Months = FakeCompanyHistoryData()
                    });

                    companyPerformance.Add(new CompanyPerformance
                    {
                        Id = companyId,
                        OverallPerformance = FakeOverallPerformance(),
                        IndustryTopPerformers = FakeIndustryTopPerformers(),
                        IndustryPeers = FakeIndustryPeers(),
                        ThemesPerformance = FakeThemesPerformance()
                    });

                    // Evaluate standard indicator trend
                    // todo uncomment next lines of code

                    //var indicators = repository.ListCompanyRpIndicators(companyId);

                    //var historicalDataIndicators = companyHistoricalDataIndicators
                    //    .Where(hdi => hdi.CompanyId == companyId && hdi.ProcessedDate == last12MonthsAgo)
                    //    .Select(hdi => hdi.Indicators)
                    //    .SingleOrDefault();

                    //if (historicalDataIndicators != null)
                    //{
                    //    foreach (var indicator in indicators)
                    //    {
                    //        int? trend = null;

                    //        var historicalDataIndicator = historicalDataIndicators
                    //            .SingleOrDefault(hdi => hdi.IndicatorNumber == indicator.Number);

                    //        if (historicalDataIndicator != null)
                    //        {
                    //            trend = 0;

                    //            if (indicator.SelectedAnswer.Score > historicalDataIndicator.RawScore)
                    //                trend = 1;

                    //            if (indicator.SelectedAnswer.Score < historicalDataIndicator.RawScore)
                    //                trend = -1;

                    //        }

                    //        // todo TEST update standard indicator trend

                    //        float? weight = null;
                    //        float? weightedScore = null;

                    //        repository.UpdateStandardIndicator(indicator.Id, trend, weight, weightedScore);
                    //    }
                    //}

                }
            });

            clientDwRepository.SaveCompanyPerformance(companyPerformance.ToList());
            clientDwRepository.SaveCompanyHistoricalPerformance(historicalPerformance.ToList());

            sw.Stop();
            syncContext.Report.Add(
                string.Format("Update standard indicators with history data completed successfully. Elapsed time: {0}",
                    sw.Elapsed));

            return syncContext;
        }

        // todo remove the fake data and replace with valid data

        private OverallPerformance FakeOverallPerformance()
        {
            return new OverallPerformance
            {
                CompanyScore = 50,
                CompanyRank = 1,
                CompanyCount = 100,
                Percentile = 50,
                EnvironmentScore = 50,
                SocialScore = 50,
                GovernanceScore = 50,
                CompanyAssessment = new Assessment {Id = 0, Name = "Average Performer"},
                EnvironmentAssessment = new Assessment {Id = 0, Name = "Average Performer"},
                SocialAssessment = new Assessment {Id = 0, Name = "Average Performer"},
                GovernanceAssessment = new Assessment {Id = 0, Name = "Average Performer"},
            };
        }

        private List<CompanyScore> FakeIndustryTopPerformers()
        {
            return new List<CompanyScore>
            {
                new CompanyScore()
                {
                    CompanyName = "Company 1",
                    Score = 50,
                    Rank = 1
                },
                new CompanyScore()
                {
                    CompanyName = "Company 2",
                    Score = 45,
                    Rank = 2
                },
                new CompanyScore()
                {
                    CompanyName = "Company 3",
                    Score = 40,
                    Rank = 3
                },
                new CompanyScore()
                {
                    CompanyName = "Company 4",
                    Score = 35,
                    Rank = 4
                },
                new CompanyScore()
                {
                    CompanyName = "Company 5",
                    Score = 30,
                    Rank = 5
                }
            };
        }

        private List<CompanyScore> FakeIndustryPeers()
        {
            return new List<CompanyScore>()
            {
                new CompanyScore
                {
                    CompanyName = "Company 1",
                    Score = 70.6,
                    Rank = 1,
                    MarkerCapitalization = 144000
                },
                new CompanyScore()
                {
                    CompanyName = "Company 2",
                    Score = 67.4,
                    Rank = 2,
                    MarkerCapitalization = 100000
                },
                new CompanyScore()
                {
                    CompanyName = "Company 3",
                    Score = 64.3,
                    Rank = 3,
                    MarkerCapitalization = 100000
                },
                new CompanyScore()
                {
                    CompanyName = "Company 4",
                    Score = 64.1,
                    Rank = 4,
                    MarkerCapitalization = 100000
                },
                new CompanyScore()
                {
                    CompanyName = "Company 5",
                    Score = 62.3,
                    Rank = 5,
                    MarkerCapitalization = 89000
                }
            };
        }

        private List<ThemePerformance> FakeThemesPerformance()
        {
            return new List<ThemePerformance>
            {
                new ThemePerformance
                {
                    ThemeName = "Environment",
                    Weight = 0.35f,
                    Score = 49,
                    Assessment = "Average Performer",
                    Rank = 50,
                    Count = 70,
                    Percentile = 29
                },
                new ThemePerformance
                {
                    ThemeName = "Social",
                    Weight = 0.4f,
                    Score = 48,
                    Assessment = "Average Performer",
                    Rank = 56,
                    Count = 70,
                    Percentile = 20
                },
                new ThemePerformance
                {
                    ThemeName = "Governance",
                    Weight = 0.25f,
                    Score = 75,
                    Assessment = "Average Performer",
                    Rank = 16,
                    Count = 70,
                    Percentile = 78
                }
            };
        }

        private List<CompanyHistoryData> FakeCompanyHistoryData()
        {
            var companyHistoricalPerformance = new List<CompanyHistoryData>();

            var currentDate = DateTime.Now.Date;

            for (var month = 1; month <= 36; month++)
            {
                var date = currentDate.AddMonths(-1 * month);

                var companyHistoryData = new CompanyHistoryData
                {
                    Date = date,
                    OverallBestInClass = 80,
                    OverallAverage = 60,
                    OverallScore = 40,
                    EnvironmentBestInClass = 80,
                    EnvironmentAverage = 60,
                    EnvironmentScore = 40,
                    SocialBestInClass = 80,
                    SocialAverage = 60,
                    SocialScore = 40,
                    GovernanceBestInClass = 80,
                    GovernanceAverage = 60,
                    GovernanceScore = 40
                };

                companyHistoricalPerformance.Add(companyHistoryData);
            }
            return companyHistoricalPerformance;
        }


        //todo use to esg ratings in preparation syncstep
        
        private CompanyReportDataOffline FillESGData(CompanyReportDataOffline crdo, ESGRatingsAdapter esgRatingsAdapter)
        {
            var companyId = crdo.CompanyId;

        //    crdo.OverallPerformance = esgRatingsAdapter.GetCompanyPerformance(companyId, crdo.CorporateData.CompanyName);

        //    crdo.IndustryTopPerformers = esgRatingsAdapter.ComparativeGroupTop5ByCompanyId(companyId);

        //    crdo.IndustryPeers = esgRatingsAdapter.GetIndustryPeers(companyId);

            return crdo;
        }

        private void ComputeKEIAggregates(IEnumerable<CompanyReportDataOffline> batch, ESGRatingsAdapter adapter, KEIPersistance persistance)
        {
            foreach (var crdo in batch)
            {
                if (crdo == null || crdo.KeyEsgIssues == null)
                    continue;

                foreach (var item in crdo.KeyEsgIssues)
                {
                    if (item.KeyEsgIssueIndicators == null)
                        continue;

                    foreach (var keiIndicator in item.KeyEsgIssueIndicators)
                    {
                        if (adapter.FillIndicatorsAggregates(crdo.CompanyId, keiIndicator))
                        {
                            if (persistance != null)
                                persistance.Push(crdo.CompanyId, keiIndicator.Number, keiIndicator.Score, keiIndicator.Average, keiIndicator.BestPractice, keiIndicator.MaterialBestPracticeGap);
                        }
                    }
                }
            }
        }

        public void Cancel()
        {
        }

        public void Abort()
        {
        }
    }
}
